/*
 * Kindlegen.java
 *
 *  created: 9.8.2012
 *  charset: UTF-8
 */

package cz.mp.k3bg.core;

import cz.mp.k3bg.Application;
import cz.mp.k3bg.log.LoggerManager;
import cz.mp.util.StringUtils;
import cz.mp.util.app.ApplicationUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Platný spustitelný příkaz spuštění programu {@code kindlegen}.
 * 
 * @author Martin Pokorný
 * @version 0.1.2
 */
public final class Kindlegen {

    private static final boolean DEBUG = false;
    private static final Logger logger =
            LoggerManager.getLogger(Kindlegen.class, DEBUG);
    
    private static Kindlegen lastValidKindlegen = null;
    
    /** Příkaz {@code kindlegen}, s cestou k němu, pokud musí být. */
    private String command = null;

    private String version = null;        
        
    private static final String KINDLEGEN = "kindlegen";
    
    /**
     * Verze programu kindlegen, do které (včetně) se pro 
     * použití unikódu (UTF-8) musí použít přepínač {@code -unicode}.
     * Vyšší verze automaticky pracují s unicode.
     */
    private static final String LAST_NO_DEFAULT_UNICODE_VERSION = "1.1";
    
    /** 
     * Přepínač pro vynucení kódování UTF-8 u verzí, 
     * kde UTF-8 není výchozí kódovnání.
     * @see #isLastValidKindlegen(java.lang.String) 
     */
    public static final String FORCE_UNICODE_OPT = "-unicode";
    
    /** Přepínač pro nejlepší kompresi. */
    public static final String C2_OPT = "-c2";
    
    public static final String O_OPT = "-o";
        
    /**
     * Seznam potencionálních (běžných) umístění příkazů {@code kindlegen}.
     * programu {@code kindlegen} v OS.
     * 
     */
    private static final String[] PREFERRED_KINDLEGEN_LOCATIONS = new String[] {
        // * obecně
        KINDLEGEN,    // (kindlegen v Path nebo v bin nebo podobně)
        // * MS-Windows:
        "C:\\Program Files\\KindleGen\\kindlegen.exe",
        "C:\\Program Files\\Amazon\\KindleGen\\kindlegen.exe",
        "C:\\Program Files\\"+Application.NAME+"\\kindlegen.exe",
        "C:\\Program Files\\"+Application.NAME+"\\kindlegen\\kindlegen.exe",
        Application.HOME_DIR+"\\kindlegen\\kindlegen.exe",
        Application.HOME_DIR+"\\kindlegen.exe",
        Application.HOME_DIR+"\\Documenty\\kindlegen.exe",
        Application.HOME_DIR+"\\Documenty\\kindlegen\\kindlegen.exe",
        Application.HOME_DIR+"\\Documents\\kindlegen.exe",
        Application.HOME_DIR+"\\Documents\\kindlegen\\kindlegen.exe",
        // * Linux (Unix-like):
        "/opt/kindlegen/kindlegen",
        "/opt/KindleGen/kindlegen",
        "/opt/Kindlegen/kindlegen",
        "/opt/Amazon/kindlegen/kindlegen",
        "/opt/Amazon/KindleGen/kindlegen",
        "/opt/"+Application.NAME+"/kindlegen",
        "/opt/"+Application.NAME+"/kindlegen/kindlegen",
        "/usr/local/kindlegen/kindlegen",
        "/usr/local/Amazon/kindlegen/kindlegen",
    };     
    
    // -----
    
    /**
     * 
     * @param command
     * @param version 
     */
    private Kindlegen(String command, String version) {
        this.command = command;
        this.version = version;
    }
    
    
    /**
     * 
     * @param kindlegenOutputLine  řádka výstupu programu {@code kindlegen}
     * @return  číslo verze programu nebo {@code null}, pokud se nepodaří v
     *      zadané řádce číslo verze najít
     */
    private static String parseVersion(String kindlegenOutputLine) {
        String result = null;
        
        // např. "Amazon.com kindlegen(Linux)   V1.2 build 33307"
        Pattern pattern = Pattern.compile(
                "\\s*(\\d[\\d\\.\\w]*)\\s*build\\s\\d+");
        Matcher matcher = pattern.matcher(kindlegenOutputLine);
        if (matcher.find()) {
            String v = matcher.group(1);
            if (! StringUtils.isBlank(v)) {
                result = v;
            }
        }
        
        return result;
    }
    
    /**
     * 
     * @param command
     * @return 
     */
    private static boolean isLastValidKindlegen(String command) {
        if (lastValidKindlegen == null) {
            return false;
        }
        if (lastValidKindlegen.getVersion() == null) {
            return false;
        }
        return lastValidKindlegen.getCommand().equals(command);
    }
    
    
    /**
     * Tovární metoda pro získání platného příkazu programu {@code kindlegen}.
     * 
     * @param command  příkaz, který má být považován za program 
     *      {@code kindlegen}
     * @return 
     */
    public static Kindlegen getKindlegen(String command) {
        if (isLastValidKindlegen(command)) {
            return lastValidKindlegen;
        }
        
        if (! canBeKindlegen(command)) {
            return null;
        }
        
        String version = runCommandAndGetVersion(command);
        
        if (! StringUtils.isBlank(version)) {
            logger.fine(command + " ... kindlegen version " + version);
            Kindlegen result = new Kindlegen(command, version);
            lastValidKindlegen = result;
            return result;
        }
        else {
            logger.fine(command + " ... IS NOT kindlegen");
            return null;
        }
    }

    /**
     * 
     * @param command
     * @return  {@code true}, pokud má smysl testovat zadaný příkaz
     * @see #getKindlegen(java.lang.String) 
     */
    private static boolean canBeKindlegen(String command) {
        // zadaný příkaz se vykoná, je proto třeba nejprve 
        //  odfiltrovat příkazy, které nemůžou být kindlegen, a
        //  mohou být i problémové (zaseknou tento program, 
        //  udělají něco co nemají atd.;  např. dir,pause,...)
        String name = new File(command).getName();
        if (StringUtils.isBlank(name) ||
                ! name.toLowerCase().contains(KINDLEGEN)) {
            logger.fine(command + " ... IS NOT kindlegen command"); 
            return false;
        }

        // přeskočit ty, které nemá smysl testovat zda jsou platným kindlegen,
        //  (protože jsou to neexisující nebo neplatné soubory)
        if (command.startsWith("C:") && !Application.OS_IS_WINDOWS) {
            return false;
        }
        if (command.contains("\\") && !Application.OS_IS_WINDOWS) {
            return false;
        }
        if (command.contains("/") && Application.OS_IS_WINDOWS) {
            return false;
        }
        if ((command.contains("\\") 
                || command.contains("/")) && 
                ! new File(command).exists()) {
            return false;
        }
        
        return true;
    }
        
    /**
     * 
     * @param command
     * @return  verzi programu {@code kindlegen} nebo {@code null}, pokud
     *      z výstupu zadaného příkazu nepodaří verzi najít.
     * @see #getKindlegen(java.lang.String) 
     */
    private static String runCommandAndGetVersion(String command) {
        String resultVersion = null;
        
        // otestuje zda lze zadaný příkaz spustit 
        //  a zda lze považovat za kindlegen
        BufferedReader br = null;
        try {
            Process cProcess = Runtime.getRuntime().exec(command);
            
            br = new BufferedReader(
                    new InputStreamReader(
                        cProcess.getInputStream()));
        
            String line;
            while ((line = br.readLine()) != null) {
                // verze je na řádce obasahující "Amazon.com kindlegen"
                // např.:  "Amazon.com kindlegen(Linux)   V1.2 build 33307"
                if (line.contains(KINDLEGEN)) {
                    resultVersion = parseVersion(line);                            
                    break;
                }
            }
            
        } catch (IOException ex) {
            // nic
        }
        finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException ex) {
                // nic
            }
        }
        return resultVersion;
    }
    
    /**
     * Pokusí se najít platný příkaz {@code kindlegen} v běžných umístěních.
     * 
     * @return 
     * @see #getKindlegen(java.lang.String) 
     */
    public static Kindlegen findKindlegen() {
        logger.finer("");
        for (String command : PREFERRED_KINDLEGEN_LOCATIONS) {
            Kindlegen kindlegen = getKindlegen(command);
            if (kindlegen != null) {                
                return kindlegen;
            }
        }
        return null;        
    }

    /**
     * 
     * @return 
     */
    public String getCommand() {
        return command;
    }

    /**
     * 
     * @return 
     */
    public String getVersion() {
        return version;
    }    

    /**
     *
     * @return {@code true}, pokud zadaný program {@code kindlegen} je ve verzi,
     *      která ještě nepracuje v unicode ve výchozím stavu.
     * @see #LAST_NO_DEFAULT_UNICODE_VERSION
     */
    public boolean isNoUnicodeVersion() {
        int comparation = ApplicationUtils.compareVersions(
                version, LAST_NO_DEFAULT_UNICODE_VERSION);
        return comparation <= 0;
    }    
    
    
//    /** */
//    public static void main(String[] args) {
//        Kindlegen kindlegen = Kindlegen.findKindlegen();
////        Kindlegen kindlegen = Kindlegen.getKindlegen("kindlegen");
////        Kindlegen kindlegen = Kindlegen.getKindlegen("error_no_kindlegen");
//        if (kindlegen != null) {
//            System.out.println("kindlegen ... command = " + kindlegen.getCommand() + " ... version = " + kindlegen.getVersion());
//        }
//        else {
//            System.out.println("kindlegen = null");
//        }
//    }    
    
}   // Kindlegen


// -----------------------------------------------------------------------------

//*********************************************************
//* Amazon.com kindlegen(Linux) V2.7 build 1019-d6e4792   *
//* A command line e-book compiler                        *
//* Copyright Amazon.com 2012                             *
//*********************************************************
//
//Usage : kindlegen filename.opf/.htm/.html/.epub [-c0 or -c1 or c2] [-verbose] [-western] [-o <file name>]
//Options:
//   -c0: no compression
//   -c1: standard DOC compression
//   -c2: Kindle huffdic compression
//   -o <file name>: Specifies the output file name. Output file will be created in the same directory as that of input file. <file name> should not contain directory path.
//   -verbose: provides more information during ebook conversion
//   -western: force build of Windows-1252 book
//   -releasenotes: display release notes
//   -gif: images are converted to GIF format (no JPEG in the book)
//   -locale <locale option> : To display messages in selected language
//      en: English
//      de: German
//      fr: French
//      it: Italian
//      es: Spanish
//      zh: Chinese
//      ja: Japanese
//      pt: Portuguese

// -----------------------------------------------------------------------------

//*********************************************************
//* Amazon.com kindlegen(Windows) V2.5 build 0626-3a91e28 *
//* A command line e-book compiler                        *
//* Copyright Amazon.com 2012                             *
//*********************************************************
//
//Usage : kindlegen filename.opf/.htm/.html/.epub [-c0 or -c1 or c2] [-verbose] [-western] [-o <file name>] 
//Options: 
//   -c0: no compression 
//   -c1: standard DOC compression 
//   -c2: Kindle huffdic compression 
//   -o <file name>: Specifies the output file name. Output file will be created in the same directory as that of input file. <file name> should not contain directory path. 
//   -verbose: provides more information during ebook conversion 
//   -western: force build of Windows-1252 book 
//   -releasenotes: display release notes 
//   -gif: images are converted to GIF format (no JPEG in the book) 
//   -locale <locale option> : To display messages in selected language 
//      en: English
//      de: German
//      fr: French
//      it: Italian
//      es: Spanish
//      zh: Chinese
//      ja: Japanese
//      pt: Portuguese

// -----------------------------------------------------------------------------

//**************************************************
//* Amazon.com kindlegen(Linux) V2.4 build 69900   *
//* A command line e-book compiler                 *
//* Copyright Amazon.com 2012                      *
//**************************************************
//
//Usage : kindlegen filename.opf/.htm/.html/.epub [-c0 or -c1 or c2] [-verbose] [-western] [-o <file name>]
//Options:
//   -c0: no compression
//   -c1: standard DOC compression
//   -c2: Kindle huffdic compression
//   -o <file name>: Specifies the output file name. Output file will be created in the same directory as that of input file. <file name> should not contain directory path.
//   -verbose: provides more information during ebook conversion
//   -western: force build of Windows-1252 book
//   -releasenotes: display release notes
//   -gif: images are converted to GIF format (no JPEG in the book)
//   -locale <locale option> : To display messages in selected language
//      en: English
//      de: German
//      fr: French
//      it: Italian
//      es: Spanish
//      zh: Chinese
//      ja: Japanese

// -----------------------------------------------------------------------------

//**************************************************
//* Amazon.com kindlegen(Linux) V2.3 build 36043   *
//* A command line e-book compiler                 *
//* Copyright Amazon.com 2011                      *
//**************************************************
//
//Usage : kindlegen filename.opf/.htm/.html/.epub [-c0 or -c1 or c2] [-verbose][-rebuild] [-onlydeps or -nodeps] [-western] [-o <file name>] 
//Options: 
//   -c0: no compression 
//   -c1: standard DOC compression 
//   -c2: Kindle huffdic compression 
//   -o <file name>: Specifies the output file name. Output file will be created in the same directory as that of input file. <file name> should not contain directory path. 
//   -verbose: verbose output 
//   -rebuild: rebuilds all dependencies 
//   -onlydeps: build only needed dependencies 
//   -nodeps: do not check/build dependencies 
//   -western: force build of Windows-1252 book 
//   -releasenotes: display release notes 
//   -gif: images are converted to GIF format (no JPEG in the book) 
//   -locale <locale option> 
//      en: To display log messages in english.
//      de: Um Log-Meldungen in Deutsch.
//      fr: Pour afficher les messages du journal en français.
//      it: Per visualizzare i messaggi di log in italiano.
//      es: Para mostrar los mensajes de registro en español.

// -----------------------------------------------------------------------------

//**************************************************
//* Amazon.com kindlegen(Windows) V2.3 build 36043 *
//* A command line e-book compiler                 *
//* Copyright Amazon.com 2011                      *
//**************************************************
//
//Usage : kindlegen filename.opf/.htm/.html/.epub [-c0 or -c1 or c2] [-verbose][-rebuild] [-onlydeps or -nodeps] [-western] [-o <file name>] 
//Options: 
//   -c0: no compression 
//   -c1: standard DOC compression 
//   -c2: Kindle huffdic compression 
//   -o <file name>: Specifies the output file name. Output file will be created in the same directory as that of input file. <file name> should not contain directory path. 
//   -verbose: verbose output 
//   -rebuild: rebuilds all dependencies 
//   -onlydeps: build only needed dependencies 
//   -nodeps: do not check/build dependencies 
//   -western: force build of Windows-1252 book 
//   -releasenotes: display release notes 
//   -gif: images are converted to GIF format (no JPEG in the book) 
//   -locale <locale option> 
//      en: To display log messages in english.
//      de: Um Log-Meldungen in Deutsch.
//      fr: Pour afficher les messages du journal en français.
//      it: Per visualizzare i messaggi di log in italiano.
//      es: Para mostrar los mensajes de registro en español.

// -----------------------------------------------------------------------------

//**************************************************
//* Amazon.com kindlegen(Linux)   V1.2 build 33307 *
//* A command line e-book compiler                 *
//* Copyright Amazon.com 2011                      *
//**************************************************
//
//Usage : kindlegen filename.opf/.htm/.html/.epub [-c0 or -c1 or c2] [-verbose] [-rebuild] [-onlydeps or -nodeps] [-western] [-o <file name>]
//Options:
//   -c0: no compression
//   -c1: standard DOC compression
//   -c2: Kindle huffdic compression
//   -o <file name>: Specifies the output file name. Output file will be created in the same directory as that of input file. <file name> should not contain directory path.
//   -verbose: verbose output
//   -rebuild: rebuilds all dependencies
//   -onlydeps: build only needed dependencies
//   -nodeps: do not check/build dependencies
//   -western: force build of Windows-1252 book
//   -releasenotes: display release notes
//   -gif: images are converted to GIF format (no JPEG in the book)

// -----------------------------------------------------------------------------

//**************************************************
//* Amazon.com kindlegen(Windows) V1.2 build 33307 *
//* A command line e-book compiler                 *
//* Copyright Amazon.com 2011                      *
//**************************************************
//
//Usage : kindlegen filename.opf/.htm/.html/.epub [-c0 or -c1 or c2] [-verbose] [-rebuild] [-onlydeps or -nodeps] [-western] [-o <file name>]
//Options:
//   -c0: no compression
//   -c1: standard DOC compression
//   -c2: Kindle huffdic compression
//   -o <file name>: Specifies the output file name. Output file will be created in the same directory as that of input file. <file name> should not contain directory path.
//   -verbose: verbose output
//   -rebuild: rebuilds all dependencies
//   -onlydeps: build only needed dependencies
//   -nodeps: do not check/build dependencies
//   -western: force build of Windows-1252 book
//   -releasenotes: display release notes
//   -gif: images are converted to GIF format (no JPEG in the book)

// -----------------------------------------------------------------------------

//***********************************************
//* Amazon.com kindlegen(Windows) V1.1 build 99 *
//* A command line e-book compiler              *
//* Copyright Amazon.com 2010                   *
//***********************************************
//
//Usage : kindlegen filename.opf/.htm/.html/.epub [-lowpriority] [-nomin] [-c0 or -c1 or c2] [-verbose] [-nocopypaste] [-rebuild] [-onlydeps or -nodeps] [-unicode] [-o <file name>]
//Options:
//   -c0: no compression
//   -c1: standard DOC compression
//   -c2: Kindle huffdic compression
//   -o <file name>: create the output file named <file name>.Do not specify directory location in <file name>. Create output mobi file in same directory as .opf file. 
//   -verbose: verbose output
//   -nocopypaste: does not allow any copy paste of content in Reader
//   -nomin: do not minimize version
//   -rebuild: rebuilds all dependencies
//   -onlydeps: build only needed dependencies
//   -nodeps: do not check/build dependencies
//   -unicode: force build of Unicode book
//   -lowpriority: set the KINDLEGEN thread priority to low (background build)
//   -releasenotes: display release notes
//   -gif: images are converted to GIF format (no JPEG in the book)

// -----------------------------------------------------------------------------

// NOT SUPPORTED :

// -----------------------------------------------------------------------------

//*************************************
//* Kindle Creator V6.01 build 41 *
//* Copyright Amazon.com 2003-2007 *
//*************************************
//
//Usage : KindleCreator filename.opf/.htm/.html/.epub [-lowpriority] [-nomin] [-c0 or -c1 or c2] [-s0 or -s1 or -s2] [-kindle] [-vouchers=n] [-nocopypaste] [-rebuild] [-onlydeps or -nodeps] [-unicode]
//Options:
// -c0: no compression
// -c1: standard DOC compression
// -c2: Mobipocket huffdic compression
// -v0: quiet mode
// -v1: verbose level one (default)
// -v : maximum verbose level
// -s0: no security
// -s1: encrypted content
// -s2: PID secured (retargetable) Mobipocket ebook
// -kindle: syntax checking for compatibility with the kindle
// -vouchers=n: [by default] use DRM v2 with n vouchers (min = 6).
// -nocopypaste: does not allow any copy paste of content in Reader
// -nomin: do not minimize version
// -rebuild: rebuilds all dependencies
// -onlydeps: build only needed dependencies
// -nodeps: do not check/build dependencies
// -unicode: force build of Unicode book
// -lowpriority: set the PRCGEN thread priority to low (background build)
// -releasenotes: display release notes
// -gif: images are converted to GIF format (no JPEG in the book)

// -----------------------------------------------------------------------------

//*****************************************
//* Mobipocket mobigen.exe V6.2 build 43  *
//* A command line e-book compiler        *
//* Copyright Mobipocket.com 2003-2008    *
//*****************************************
//
//Usage : mobigen filename.opf/.htm/.html/.epub [-lowpriority] [-nomin] [-c0 or -c1 or c2] [-s0 or -s1 or -s2] [-verbose] [-vouchers=n] [-nocopypaste] [-rebuild] [-onlydeps or -nodeps] [-unicode]
//Options:
//   -c0: no compression
//   -c1: standard DOC compression
//   -c2: Mobipocket huffdic compression
//   -s0: no security
//   -s1: encrypted content
//   -s2: PID secured (retargetable) Mobipocket ebook
//   -verbose: verbose output   -vouchers=n: [by default] use DRM v2 with n vouchers (min = 6).
//   -nocopypaste: does not allow any copy paste of content in Reader
//   -nomin: do not minimize version
//   -rebuild: rebuilds all dependencies
//   -onlydeps: build only needed dependencies
//   -nodeps: do not check/build dependencies
//   -unicode: force build of Unicode book
//   -lowpriority: set the PRCGEN thread priority to low (background build)
//   -regserver: register the XOPFPlugin Type Library
//   -unregserver: unregister the XOPFPlugin Type Library
//   -releasenotes: display release notes
//   -gif: images are converted to GIF format (no JPEG in the book)

// -----------------------------------------------------------------------------

// Kindlegen.java